package util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

public class PacGenerator {
	
	private String userRuleText;
	
	public PacGenerator(String userRuleText) {
		this.userRuleText = userRuleText;
	}
	
	private String getGFWList() {
		BufferedReader gfwlistR = null;
		try {
			URL gfwlistUrl = new URL("http://autoproxy-gfwlist.googlecode.com"
					+ "/svn/trunk/gfwlist.txt");
			URLConnection gfwlistConn = gfwlistUrl.openConnection();
			gfwlistR = new BufferedReader(new InputStreamReader(
					gfwlistConn.getInputStream()));
		} catch (IOException e1) {
			//TODO:
		}

		StringBuilder gfwlistContent = new StringBuilder();

		try {
			String line = null;
			while ((line = gfwlistR.readLine()) != null) {
				gfwlistContent.append(line).append("\n");
			}
		} catch (IOException e) {
			//TODO:
		}

		return gfwlistContent.toString();
	}

	public String getRule() {
		String ruleString = Base64Coder.decodeString(this.getGFWList().replace(
				"\n", ""));
		return ruleString;
	}

	public String getPac(String hostName, int port) {
		StringBuilder pacContent = new StringBuilder();

		try {
			
			StringBuffer allRulesBuffer = new StringBuffer();
			allRulesBuffer.append(this.userRuleText).append(this.getRule());

			BufferedReader ruleR = new BufferedReader(new InputStreamReader(
					new ByteArrayInputStream(allRulesBuffer.toString().getBytes(
							"ISO-8859-1"))));

			pacContent.append("function FindProxyForURL(url, host) {").append(
					"\n");
			pacContent
					.append("\t")
					.append("var PROXY = \"SOCKS5 " + hostName + ":" + port
							+ "\";").append("\n");
			pacContent.append("\t").append("var DEFAULT = \"DIRECT\";")
					.append("\n");

			String line = null;

			File customRuleFile = new File("etc/gfwlist.txt");
			if (customRuleFile.exists()) {
				BufferedReader customeRuleR = new BufferedReader(
						new InputStreamReader(new FileInputStream(
								customRuleFile)));
				while ((line = customeRuleR.readLine()) != null) {
					pacContent.append(convertRule(line));
				}
			}

			while ((line = ruleR.readLine()) != null) {
				pacContent.append(convertRule(line));
			}
			pacContent.append("\t").append("return DEFAULT;").append("\n");
			pacContent.append("}\n");

		} catch (IOException e) {
			//TODO:
		}

		return pacContent.toString();
	}

	private String convertRule(String ruleLine) {
		if (ruleLine.isEmpty()) {
			return "";
		}

		if (ruleLine.startsWith("[") || ruleLine.startsWith("!")) {
			return "";
		}

		String returnProxy = "PROXY";
		String ruleReg = "";

		if (ruleLine.startsWith("@@")) {
			ruleLine = ruleLine.substring(2);
			returnProxy = "DEFAULT";
		}

		if (ruleLine.startsWith("||")) {
			ruleReg = "/^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?"
					+ regEncode(ruleLine.substring(2)) + "/";
		} else if (ruleLine.startsWith("|")) {
			ruleReg = "/^" + regEncode(ruleLine.substring(1)) + "/";
		} else if (ruleLine.startsWith("/") && ruleLine.endsWith("/")) {
			ruleReg = ruleLine;
		} else {
			ruleReg = "/" + regEncode(ruleLine) + "/";
		}

		StringBuilder pacLine = new StringBuilder();
		pacLine.append("\t").append("if(").append(ruleReg)
				.append("i.test(url)) return ").append(returnProxy)
				.append(";\n");
		return pacLine.toString();

	}

	private String regEncode(String str) {
		return str.replace("/", "\\/").replace(".", "\\.").replace(":", "\\:")
				.replace("%", "\\%").replace("*", ".*").replace("-", "\\-")
				.replace("&", "\\&").replace("?", "\\?");
	}
}
